#ifndef __PANEL_COMPRESSOR_H__
#define __PANEL_COMPRESSOR_H__

#include <wx/wx.h>
#include <wx/aui/aui.h>
#include <wx/wrapsizer.h>
#include <wx/event.h>
#include <wx/xml/xml.h>
#include "MyCommon.h"

class MyEventCompressor : public wxCommandEvent {
public:
    MyEventCompressor(wxEventType eventType = wxEVT_NULL,int id = 0)
        : wxCommandEvent(eventType, id) {

        }

    // 克隆事件对象
//    [[nodiscard]] // C++17 才支持，意思就是函数返回值不能被忽略，否则编译器发出警告
    virtual wxEvent *Clone() const override {
        return new MyEventCompressor(*this);
    }

    void SetAttackTime(double attack_time) {
        m_attack_time = attack_time;
    }
    void SetThreshold(double threshold) {
        m_threshold = threshold;
    }
    void SetReleaseTime(double q) {
        m_release_time = q;
    }
    void SetPostGain(double gain) {
        m_postgain = gain;
    }
    void SetRatio(double ratio) {
        m_ratio = ratio;
    }
    void SetEnable(bool enable) {
        this->enable = enable;
    }
    double GetAttackTime() {
        return m_attack_time;
    }
    double GetThreshold() {
        return m_threshold;
    }
    double GetReleaseTime() {
        return m_release_time;
    }
    double GetPostGain() {
        return m_postgain;
    }
    double GetRatio() {
        return m_ratio;
    }
    bool GetEnable() {
        return enable;
    }
    void SetPresetIndex(const unsigned int index) {
        preset_index = index;
    }
    int GetPresetIndex() {
        return preset_index;
    }

private:

    double m_threshold;
    double m_release_time;
    double m_postgain;
    double m_ratio;
    double m_attack_time;
    bool enable;
    int preset_index;
};

wxDECLARE_EVENT(myEVT_COMPRESSOR, MyEventCompressor);
wxDECLARE_EVENT(myEVT_COMPRESSOR_ATTACK_TIME, MyEventCompressor);
wxDECLARE_EVENT(myEVT_COMPRESSOR_THRESHOLD, MyEventCompressor);
wxDECLARE_EVENT(myEVT_COMPRESSOR_RELEASE_TIME, MyEventCompressor);
wxDECLARE_EVENT(myEVT_COMPRESSOR_POSTGAIN, MyEventCompressor);
wxDECLARE_EVENT(myEVT_COMPRESSOR_RATIO, MyEventCompressor);
wxDECLARE_EVENT(myEVT_COMPRESSOR_ENABLE, MyEventCompressor);

typedef void (wxEvtHandler::*MyCompressorEventFunction)(MyEventCompressor &);

#define MyCompressorEventHandler(func) \
    wxEVENT_HANDLER_CAST(MyCompressorEventFunction, func)

#define M_EVT_COMPRESSOR(id, fn) \
    wx__DECLARE_EVT1(myEVT_COMPRESSOR, id, MyCompressorEventHandler(fn))
#define M_EVT_COMPRESSOR_ATTACK_TIME(id, fn) \
    wx__DECLARE_EVT1(myEVT_COMPRESSOR_ATTACK_TIME, id, MyCompressorEventHandler(fn))
#define M_EVT_COMPRESSOR_THRESHOLD(id, fn) \
    wx__DECLARE_EVT1(myEVT_COMPRESSOR_THRESHOLD, id, MyCompressorEventHandler(fn))
#define M_EVT_COMPRESSOR_RELEASE_TIME(id, fn) \
    wx__DECLARE_EVT1(myEVT_COMPRESSOR_RELEASE_TIME, id, MyCompressorEventHandler(fn))
#define M_EVT_COMPRESSOR_POSTGAIN(id, fn) \
    wx__DECLARE_EVT1(myEVT_COMPRESSOR_POSTGAIN, id, MyCompressorEventHandler(fn))
#define M_EVT_COMPRESSOR_RATIO(id, fn) \
    wx__DECLARE_EVT1(myEVT_COMPRESSOR_RATIO, id, MyCompressorEventHandler(fn))
#define M_EVT_COMPRESSOR_ENABLE(id, fn) \
    wx__DECLARE_EVT1(myEVT_COMPRESSOR_ENABLE, id, MyCompressorEventHandler(fn))

class PanelCompressor : public wxPanel
{
public:
    PanelCompressor(const wxString &title, wxXmlNode *node, wxWindowID id = wxID_ANY, wxWindow *parent = nullptr);
    typedef struct
    {
        bool enable;
        float threshold;
        float ratio;
        float attack_time;
        float release_time;
        float postgain;
    }param_struct;

private:

    enum{
        EV_ENABLE = 1,
        EV_THRESHOLD,
        EV_RATIO,
        EV_ATTACK_TIME,
        EV_RELEASE_TIME,
        EV_POSTGAIN,
    };

    const double threshold_max = 0.1;
    const double threshold_min = -30;
    const double threshold_step = 0.01;
    const double postgain_max = 12;
    const double postgain_min = -12;
    const double postgain_step = 0.01;
    const double ratio_max = 20;
    const double ratio_min = 1;
    const double ratio_step = 0.01;
    const double attack_time_max = 0.5;
    const double attack_time_min = 0;
    const double attack_time_step = 0.001;
    const double release_time_max = 1;
    const double release_time_min = 0.001;
    const double release_time_step = 0.001;

    const char *attr_name_select = "select";
    const char *attr_name_preset_default = "default";
    const char *attr_name_param_enable = "enable";
    const char *attr_name_param_threshold = "threshold";
    const char *attr_name_param_release_time = "release_time";
    const char *attr_name_param_postgain = "postgain";
    const char *attr_name_param_ratio = "ratio";
    const char *attr_name_param_attack_time = "attack_time";

    wxWindowID ID_TXT_THRESHOLD;
    wxWindowID ID_TXT_RELEASE_TIME;
    wxWindowID ID_TXT_POSTGAIN;
    wxWindowID ID_TXT_RATIO;
    wxWindowID ID_TXT_ATTACK_TIME;
    wxWindowID ID_SLI_THRESHOLD;
    wxWindowID ID_SLI_RELEASE_TIME;
    wxWindowID ID_SLI_POSTGAIN;
    wxWindowID ID_SLI_RATIO;
    wxWindowID ID_SLI_ATTACK_TIME;
    wxWindowID ID_CHK_SWITCH;
    wxWindowID ID_CHO_PRESET;


    wxAuiPaneInfo paneInfo;
    MyEventCompressor param_event;
    param_struct param;
    wxXmlNode *root_node;
    wxXmlNode *preset_node;
    int select_index;

public:
    wxAuiPaneInfo &GetPaneInfo();
    void SetShow(bool show);
    double SetParamThreshold(double value);
    double SetParamReleaseTime(double value);
    double SetParamPostGain(double value);
    double SetParamRatio(double value);
    double SetParamAttackTime(double value);
    bool SetParamEnable(bool value);;
    double GetParamThreshold();
    double GetParamReleaseTime();
    double GetParamPostGain();
    double GetParamRatio();
    double GetParamAttackTime();
    bool GetParamEnable();
    void SetPresetIndex(const unsigned int index);
    int GetPresetIndex();
    void PresetListClear(void);
    void AddPresetList(const wxString &preset_name);
    wxXmlNode *SaveCurrentParamsToNewPreset(wxXmlNode *root, const wxString &new_preset_name,int &is_same);
    wxXmlNode *WriteToXML(wxXmlNode *node);

private:
    void OnSliderChange(wxCommandEvent& event);
    void OnTextEnter(wxCommandEvent& event);
    void OnChkChange(wxCommandEvent& event);
    void OnCombChange(wxCommandEvent& event);

    void TrigerEvent(int ev);
    wxXmlNode *SelectPreset(wxString name);

    // wxDECLARE_EVENT_TABLE();
};


#endif
